﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;

namespace ImageEffect.Effects
{
    public abstract class ScanlineEffect : Effect
    {
        private int _interval = 20;
        private Color _color = Color.White;

        [CategoryAttribute("Effect Settings"),
         DisplayNameAttribute("Color"),
         Editor(typeof(ColorTypeEditor), typeof(UITypeEditor))]
        public Color Color { get { return _color; } set { _color = value; } }

        [CategoryAttribute("Effect Settings"),
         DefaultValueAttribute(20),
         DisplayNameAttribute("Spacing")]
        public int Interval { get { return _interval; } set { _interval = Math.Max(value, 1); } }

        [CategoryAttribute("Effect Settings"),
         DefaultValue(false),
         DisplayNameAttribute("Logrithmic")]
        public bool Logrithmic { get; set; }

        public ScanlineEffect(string name)
            : base(name)
        {
        }
    }

    public sealed class Scanlines : ScanlineEffect
    {
        public int Angle { get; set; }

        public Scanlines()
            : base("Scanlines")
        {
            Angle = 0;
        }

        public override void Apply(Bitmap bmp)
        {
            // First create a clear bitmap
            int sideLength = (int)(Math.Sqrt(bmp.Width * bmp.Width + bmp.Height * bmp.Height));

            Bitmap slbmp = new Bitmap(sideLength, sideLength, bmp.PixelFormat);
            Graphics gfx = Graphics.FromImage(slbmp);
            gfx.Clear(Color.FromArgb(0, 0, 0, 0));

            // Draw our scanlines
            for (int y = 0; y < slbmp.Height; y += this.Interval)
            {
                gfx.DrawLine(
                    new Pen(this.Color),
                    new Point(0, y),
                    new Point(slbmp.Width, y)
                );
            }

            // Set up our target image
            gfx = Graphics.FromImage(bmp);

            // Rotate our canvas
            gfx.ResetTransform();
            gfx.TranslateTransform((float)bmp.Width / 2, (float)bmp.Height / 2);
            gfx.RotateTransform((float)this.Angle);
            gfx.TranslateTransform(-(float)slbmp.Width / 2, -(float)slbmp.Height / 2);

            // Apply the bitmap to our image
            gfx.DrawImage(
                slbmp,
                new Point(0, 0)
            ); 
        }
    }

    public sealed class HorizontalScanlines : ScanlineEffect
    {
        public HorizontalScanlines()
            : base("Horizontal Scanlines")
        {
        }

        public override void Apply(Bitmap bmp)
        {
            for (int y = 0; y < bmp.Height; y += this.Interval)
            {
                Graphics.FromImage(bmp).DrawLine(
                    new Pen(this.Color),
                    new Point(0, y),
                    new Point(bmp.Width, y)
                );
            }
        }
    }

    public sealed class VerticalScanlines : ScanlineEffect
    {
        public VerticalScanlines()
            : base("Vertical Scanlines")
        {
        }

        public override void Apply(Bitmap bmp)
        {
            for (int x = 0; x < bmp.Width; x += this.Interval)
            {
                Graphics.FromImage(bmp).DrawLine(
                    new Pen(this.Color),
                    new Point(x, 0),
                    new Point(x, bmp.Height)
                );
            }
        }
    }

    public sealed class DiagonalScanlines : ScanlineEffect
    {
        public DiagonalScanlines()
            : base("Diagonal Scanlines")
        {
        }

        public override void Apply(Bitmap bmp)
        {
            double aspect = (double)bmp.Height / (double)bmp.Width;

            double yPos = 0;
            int interval = this.Interval;

            for (int x = 0; x < bmp.Width * 2; x += interval, yPos += aspect * (double)interval)
            {
                Graphics.FromImage(bmp).DrawLine(
                    new Pen(this.Color),
                    new Point(0, (int)yPos),
                    new Point(x, 0)
                );
            }
        }
    }
}
